//
// Created by 26364 on 2025/10/28.
//

#include "My_InFlash.h"


/* 准备写入的测试数据（32位） */
uint32_t dat[8] = {0x12345678, 0x87654321, 0x9ABCDEF0, 0xFEDCBA98, 0x76543210, 0xFEDCBA98, 0x76543210};
uint32_t* p = (uint32_t*)dat;
#define FLASH_USER_START_ADDR   ADDR_FLASH_SECTOR_6_BANK1
#define FLASH_USER_END_ADDR     ADDR_FLASH_SECTOR_7_BANK1  /* 注意：实际写入到扇区7的起始地址，若需覆盖扇区7需改为ADDR_FLASH_SECTOR_END */

/**
  * @brief  根据地址获取所在扇区编号（适配H743 Bank 1）
  * @param  Address：FLASH地址（需在Bank 1范围内）
  * @retval 扇区编号（与HAL库FLASH_SECTOR_x宏匹配）
  */
static uint32_t GetSector_BANK1(uint32_t Address) {
    uint32_t sector = 0;
    if ((Address >= ADDR_FLASH_SECTOR_0_BANK1) && (Address < ADDR_FLASH_SECTOR_1_BANK1)) {
        sector = FLASH_SECTOR_0;
    } else if ((Address >= ADDR_FLASH_SECTOR_1_BANK1) && (Address < ADDR_FLASH_SECTOR_2_BANK1)) {
        sector = FLASH_SECTOR_1;
    } else if ((Address >= ADDR_FLASH_SECTOR_2_BANK1) && (Address < ADDR_FLASH_SECTOR_3_BANK1)) {
        sector = FLASH_SECTOR_2;
    } else if ((Address >= ADDR_FLASH_SECTOR_3_BANK1) && (Address < ADDR_FLASH_SECTOR_4_BANK1)) {
        sector = FLASH_SECTOR_3;
    } else if ((Address >= ADDR_FLASH_SECTOR_4_BANK1) && (Address < ADDR_FLASH_SECTOR_5_BANK1)) {
        sector = FLASH_SECTOR_4;
    } else if ((Address >= ADDR_FLASH_SECTOR_5_BANK1) && (Address < ADDR_FLASH_SECTOR_6_BANK1)) {
        sector = FLASH_SECTOR_5;
    } else if ((Address >= ADDR_FLASH_SECTOR_6_BANK1) && (Address < ADDR_FLASH_SECTOR_7_BANK1)) {
        sector = FLASH_SECTOR_6;
    } else if ((Address >= ADDR_FLASH_SECTOR_7_BANK1) && (Address < ADDR_FLASH_SECTOR_END_BANK1)) {
        sector = FLASH_SECTOR_7;
    } else {
        /* 地址超出Bank 1范围，返回无效值（实际应用中可增加错误处理） */
        sector = 0xFF;
    }
    return sector;
}

/**
  * @brief  根据地址获取所在扇区编号（适配H743 Bank 2）
  * @param  Address：FLASH地址（需在Bank 2范围内）
  * @retval 扇区编号（与HAL库FLASH_SECTOR_x宏匹配）
  */
static uint32_t GetSector_BANK2(uint32_t Address) {
    uint32_t sector = 0;
    if ((Address >= ADDR_FLASH_SECTOR_0_BANK2) && (Address < ADDR_FLASH_SECTOR_1_BANK2)) {
        sector = FLASH_SECTOR_0;
    } else if ((Address >= ADDR_FLASH_SECTOR_1_BANK2) && (Address < ADDR_FLASH_SECTOR_2_BANK2)) {
        sector = FLASH_SECTOR_1;
    } else if ((Address >= ADDR_FLASH_SECTOR_2_BANK2) && (Address < ADDR_FLASH_SECTOR_3_BANK2)) {
        sector = FLASH_SECTOR_2;
    } else if ((Address >= ADDR_FLASH_SECTOR_3_BANK2) && (Address < ADDR_FLASH_SECTOR_4_BANK2)) {
        sector = FLASH_SECTOR_3;
    } else if ((Address >= ADDR_FLASH_SECTOR_4_BANK2) && (Address < ADDR_FLASH_SECTOR_5_BANK2)) {
        sector = FLASH_SECTOR_4;
    } else if ((Address >= ADDR_FLASH_SECTOR_5_BANK2) && (Address < ADDR_FLASH_SECTOR_6_BANK2)) {
        sector = FLASH_SECTOR_5;
    } else if ((Address >= ADDR_FLASH_SECTOR_6_BANK2) && (Address < ADDR_FLASH_SECTOR_7_BANK2)) {
        sector = FLASH_SECTOR_6;
    } else if ((Address >= ADDR_FLASH_SECTOR_7_BANK2) && (Address < ADDR_FLASH_SECTOR_END_BANK2)) {
        sector = FLASH_SECTOR_7;
    } else {
        /* 地址超出Bank 1范围，返回无效值（实际应用中可增加错误处理） */
        sector = 0xFF;
    }
    return sector;
}


/**
  * @brief  内部FLASH读写测试（适配STM32H743IIT6）
  * @retval 0：测试成功；-1：测试失败
  */
int InternalFlash_Test(void) {
    uint32_t FirstSector = 0;
    uint32_t NbOfSectors = 0;
    uint32_t SECTORError = 0;
    uint32_t Address = 0;
    __IO uint32_t Data32 = 0;
    __IO uint32_t MemoryProgramStatus = 0;
    FLASH_EraseInitTypeDef EraseInitStruct = {0};
    /* 2. FLASH解锁 */
    if (HAL_FLASH_Unlock() != HAL_OK) {
        return -1; /* 解锁失败 */
    }
    /* 3. 计算需要擦除的扇区范围 */
    FirstSector = GetSector_BANK1(FLASH_USER_START_ADDR);
    if (FirstSector == 0xFF)
        return -1; /* 起始地址无效 */
    uint32_t LastSector = GetSector_BANK1(FLASH_USER_END_ADDR - 1); /* 取结束地址的前一个字节所在扇区 */
    if (LastSector == 0xFF)
        return -1; /* 结束地址无效 */

    NbOfSectors = LastSector - FirstSector + 1; /* 包含起始和结束扇区 */
    /* 4. 配置擦除参数（适配H7） */
    EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
    EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_2; /* H7常用范围：2.1V-3.6V */
    EraseInitStruct.Sector = FirstSector;
    EraseInitStruct.NbSectors = NbOfSectors;
    EraseInitStruct.Banks = FLASH_BANK_1; /* 明确指定操作Bank 1 */
    /* 执行扇区擦除 */
    if (HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK) {
        HAL_FLASH_Lock();
        return -1; /* 擦除失败 */
    }

    /* 5. 写入数据（H7支持32位字编程） */
    Address = FLASH_USER_START_ADDR;
    while (Address < FLASH_USER_END_ADDR) {
        /* 使用H7支持的编程类型：FLASH_TYPEPROGRAM_WORD（32位） */
        if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, Address, (uint32_t)p) == HAL_OK) {
            Address += 4 * 8; /* 每次写入4*8字节 */
        } else {
            HAL_FLASH_Lock();
            return -1; /* 写入失败 */
        }
    }

    /* 6. FLASH上锁 */
    HAL_FLASH_Lock();

    /* 7. 校验写入数据 */
    Address = FLASH_USER_START_ADDR;
    MemoryProgramStatus = 0;
    while (Address < FLASH_USER_END_ADDR) {
        Data32 = *(__IO uint32_t*)Address;
        if (Data32 != dat[0]) {
            MemoryProgramStatus++;
        }
        Address += 4 * 8;
    }
    /* 返回校验结果 */
    return (MemoryProgramStatus == 0) ? 0 : -1;
}


/**
 * @brief  内部FLASH擦除函数
 * @param  startAddr: 擦除起始地址
 * @param  size: 擦除数据大小（字节）
 * @param  bank: 块
 * @retval 0：擦除成功；1：擦除失败
 */
uint8_t InternalFlash_Erase(uint32_t startAddr, uint32_t size, uint8_t bank) {
    uint32_t FirstSector = 0;
    uint32_t NbOfSectors = 0;
    uint32_t SECTORError = 0;
    FLASH_EraseInitTypeDef EraseInitStruct = {0};
    uint32_t endAddr = startAddr + size;

    /* 计算结束地址，32字节为一次，不足要补，32字节对齐 */
    uint8_t sizeComplete = size % 32;
    if (sizeComplete != 0) {
        endAddr += (32 - sizeComplete);
    }

    /* FLASH解锁 */
    if (HAL_FLASH_Unlock() != HAL_OK) {
        return 1;
    }

    /* 计算需要擦除的扇区范围 */
    if (bank == 1) {
        FirstSector = GetSector_BANK1(startAddr);
    } else {
        FirstSector = GetSector_BANK2(startAddr);
    }

    if (FirstSector == 0xFF) {
        HAL_FLASH_Lock();
        return 1;
    }
    uint32_t LastSector;
    if (bank == 1) {
        LastSector = GetSector_BANK1(endAddr - 1);
    } else {
        LastSector = GetSector_BANK2(endAddr - 1);
    }

    if (LastSector == 0xFF) {
        HAL_FLASH_Lock();
        return 1;
    }

    NbOfSectors = 1 + LastSector - FirstSector;

    /* 配置擦除参数 */
    EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
    EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_2;
    EraseInitStruct.Sector = FirstSector;
    EraseInitStruct.NbSectors = NbOfSectors;
    if (bank == 1) {
        EraseInitStruct.Banks = FLASH_BANK_1;
    } else {
        EraseInitStruct.Banks = FLASH_BANK_2;
    }


    /* 执行扇区擦除 */
    if (HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK) {
        HAL_FLASH_Lock();
        return 1;
    }

    /* FLASH上锁 */
    HAL_FLASH_Lock();

    return 0; // 擦除成功
}

/**
  * @brief  内部FLASH写入函数（带校验）
  * @param  startAddr: 写入起始地址
  * @param  data: 要写入的数据指针
  * @param  size: 要写入的数据大小（字节）
  * @retval 0：写入成功；1：写入失败
  */
uint8_t InFlash_Write(uint32_t startAddr, uint8_t* data, uint32_t size) {
    uint32_t Address = 0;
    __IO uint32_t Data32 = 0;
    __IO uint32_t MemoryProgramStatus = 0;

    uint32_t i = 0;

    /* 检查参数有效性 */
    if (data == NULL || size == 0) {
        return 1;
    }

    /* 计算结束地址，32字节为一次，不足要补，32字节对齐 */
    uint8_t sizeComplete = size % 32;
    uint32_t endAddr = startAddr + size;
    if (sizeComplete != 0) {
        endAddr += (32 - sizeComplete);
    }

    /* FLASH解锁 */
    if (HAL_FLASH_Unlock() != HAL_OK) {
        return 1;
    }

    /* 写入数据 */
    Address = startAddr;
    uint32_t totalWords = (size + 3) / 4; // 向上取整到4字节边界
    i = 0;
    while (Address < endAddr) {
        uint32_t flashWord[8];
        // 准备8个uint32_t的数据，不足部分补0
        for (int j = 0; j < 8; j++) {
            if (i + j < totalWords) {
                // 安全地从uint8_t数组中读取uint32_t值，避免越界
                uint32_t value = 0;
                uint8_t* bytePtr = (uint8_t*)&value;
                for (int k = 0; k < 4; k++) {
                    uint32_t byteIndex = (i + j) * 4 + k;
                    if (byteIndex < size) {
                        bytePtr[k] = data[byteIndex];
                    } else {
                        bytePtr[k] = 0; // 不足部分补0
                    }
                }
                flashWord[j] = value;
            } else {
                flashWord[j] = 0; // 不足部分补0
            }
        }

        if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, Address, (uint32_t)flashWord) == HAL_OK) {
            Address += 4 * 8; /* 每次写入32字节 */
            i += 8;
        } else {
            HAL_FLASH_Lock();
            return 1;
        }
    }

    /* FLASH上锁 */
    HAL_FLASH_Lock();

    /* 校验写入数据 */
    Address = startAddr;
    i = 0;
    MemoryProgramStatus = 0;
    while (Address < startAddr + size) {
        Data32 = *(__IO uint32_t*)Address;

        // 安全地从uint8_t数组中读取uint32_t值用于比较
        uint32_t expectedValue = 0;
        uint8_t* bytePtr = (uint8_t*)&expectedValue;
        for (int k = 0; k < 4; k++) {
            uint32_t byteIndex = i * 4 + k;
            if (byteIndex < size) {
                bytePtr[k] = data[byteIndex];
            } else {
                bytePtr[k] = 0;
            }
        }

        if (i < totalWords && Data32 != expectedValue) {
            MemoryProgramStatus++;
        }
        Address += 4;
        i++;
    }
    /* 返回校验结果 */
    return (MemoryProgramStatus == 0) ? 0 : 1;
}
